package com.jieao.template.common.aop;

import cn.hutool.core.net.NetUtil;
import com.jieao.template.common.annotation.NoRepeatSubmit;
import com.jieao.template.common.util.RedisUtils;
import com.jieao.template.entity.pub.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Jzw
 * @className RepeatSubmitAspect
 * @since 2020-04-13 15:49
 */
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect
{

    @Autowired
    private RedisUtils redisUtils;

    /**
     * redis 保存前缀
     */
    private final String PREFIX = "repeatSubmit_";

    @Pointcut("@annotation(noRepeatSubmit)")
    public void pointCut(NoRepeatSubmit noRepeatSubmit)
    {
    }

    @Around("pointCut(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable
    {
        int lockSeconds = noRepeatSubmit.lockTime();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        Assert.notNull(requestAttributes, "requestAttributes can not null");
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        Assert.notNull(request, "request can not null");

        // 此处可以用token或者JSessionId
        String token = request.getHeader("authorization");
        String path = request.getServletPath();
        String key = PREFIX + token + "_" + path;
        boolean isSuccess = redisUtils.setLock(key, lockSeconds);
        log.info("tryLock key = [{}],", key);

        if (isSuccess)
        {
            log.info("tryLock success, key = [{}]", key);
            // 获取锁成功
            Object result;

            try
            {
                // 执行进程
                result = pjp.proceed();
            } finally
            {
                // 解锁
                redisUtils.releaseLock(key, NetUtil.getLocalhostStr());
                log.info("releaseLock success, key = [{}] ", key);
            }
            return result;
        }
        else
        {
            // 获取锁失败，认为是重复提交的请求
            log.info("tryLock fail, key = [{}]", key);
            return JsonData.repeatSubmit();
        }

    }
}
